home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / demos / GL / libdemo / spaced.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  25KB  |  1,082 lines

  1. /*
  2.  * Copyright 1991, 1992, 1993, 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17. /*
  18.  * Spaced: The Three-D Space Editor
  19.  *
  20.  * spaced.c
  21.  *
  22.  * This file, along with it's include file, spaced.h, contains
  23.  * all necessary routines for Spaced. See the comments in the include
  24.  * file for instructions on hooking it up to your code.
  25.  *
  26.  * Howard Look
  27.  * July, 1989
  28.  * 
  29.  */
  30.  
  31. #include <gl.h>
  32. #include <device.h>
  33. #include <math.h>
  34. #include "spaced.h"
  35.  
  36. #define X 0
  37. #define Y 1
  38. #define Z 2
  39.  
  40. #define XY 2
  41. #define XZ 1
  42. #define YZ 0
  43. #define NONE -1
  44. #define EDGE_PICKED 99
  45.  
  46. /* Prototypes for internal functions */
  47. static void transform_point(
  48.     Coord *, 
  49.     Matrix, 
  50.     Scoord *);
  51. static float find_distance(
  52.     Scoord p[2], 
  53.     Scoord q[2], 
  54.     Scoord r[2]);
  55. static float cos_angle_between(
  56.     Scoord center[2],
  57.     Scoord p1[2],
  58.     Scoord p2[2]);
  59. static float dist(
  60.     Scoord p1[2], 
  61.     Scoord p2[2]);
  62. static void find_close(
  63.     Scoord m[2],
  64.     Scoord p[2], 
  65.     Scoord q[3][2][2],
  66.     short a[2][2],
  67.     int i[3][2],
  68.     int);
  69. static int length(Scoord axis[2][2]);
  70. static Boolean colinear(Scoord axis1[2][2], Scoord axis2[2][2]);
  71.  
  72.  
  73. /* window information */
  74. static long origin_x, origin_y, size_x, size_y;
  75.  
  76. /* Which plane is motion constrained to */
  77. static int plane;
  78. static int edge;
  79.  
  80.  
  81. static Coord initial_origin[3];
  82. static Scoord initial_screen_origin[2];
  83.  
  84. static Boolean line_constrain, plane_constrain, first_time, constraint_ok;
  85.  
  86. static int colinear_threshold = SP_COLINEAR_THRESHOLD;
  87. static int constraint_threshold = SP_CONSTRAINT_THRESHOLD;
  88.  
  89. static Device line_but1 = SP_LINE_BUTTON1;
  90. static Device line_but2 = SP_LINE_BUTTON2;
  91.  
  92. static Device plane_but1 = SP_PLANE_BUTTON1;
  93. static Device plane_but2 = SP_PLANE_BUTTON2;
  94.  
  95.  
  96.  
  97. /*
  98.  * Call this routine when you have completed all desired motion on a
  99.  * given point.
  100.  */
  101. void end_spaced(void)
  102. {
  103.     /* A gratuitous function for future expansion */
  104. }
  105.  
  106.  
  107. /*
  108.  * Call this routine to change any of spaced's parameters from or to
  109.  * their default values. Calling with any parameter == -1 will reset
  110.  * that parameter to its default value.
  111.  *
  112.  * See the file spaced.h for a description of parameters and their
  113.  * default values.
  114.  */
  115. void set_spaced(
  116.     int col_thresh,
  117.     int const_thresh,
  118.     Device line1,
  119.     Device line2,
  120.     Device plane1,
  121.     Device plane2)
  122. {
  123.     if (col_thresh == SP_DEFAULT)
  124.         colinear_threshold = SP_COLINEAR_THRESHOLD;
  125.     else    
  126.         colinear_threshold = col_thresh;
  127.  
  128.     if (const_thresh == SP_DEFAULT)    
  129.         constraint_threshold = SP_CONSTRAINT_THRESHOLD;
  130.     else
  131.         constraint_threshold = const_thresh;
  132.  
  133.     if (line1 == SP_DEFAULT)
  134.         line_but1 = SP_LINE_BUTTON1;
  135.     else
  136.         line_but1 = line1;
  137.         
  138.     if (line2 == SP_DEFAULT)
  139.         line_but1 = SP_LINE_BUTTON1;
  140.     else
  141.         line_but1 = line2;
  142.         
  143.     if (plane1 == SP_DEFAULT)
  144.         plane_but1 = SP_PLANE_BUTTON1;
  145.     else
  146.         plane_but1 = plane1;
  147.         
  148.     if (plane2 == SP_DEFAULT)
  149.         plane_but1 = SP_PLANE_BUTTON2;
  150.     else
  151.         plane_but1 = plane2;
  152.         
  153. }
  154.  
  155.  
  156.  
  157. void start_spaced()
  158. {
  159.     plane = NONE;
  160.     edge = NONE;
  161.     first_time = TRUE;
  162.     constraint_ok = FALSE;
  163. }
  164.  
  165. static Matrix idmat=
  166. {
  167.     1., 0., 0., 0.,
  168.     0., 1., 0., 0.,
  169.     0., 0., 1., 0.,
  170.     0., 0., 0., 1., 
  171. };
  172.  
  173. /*
  174.  * The main routine. This is what you call to do update the position
  175.  * of a three-d point in world space.
  176.  *
  177.  * M is the matrix that gets your point from its world space into screen
  178.  * space. If you are in single matrix mode, just do a getmatrix and pass
  179.  * it here. If you are in double matrix mode, you will need to multiply
  180.  * the viewing matrix by the projection matrix to get the matrix needed here.
  181.  *
  182.  * origin is the coordinates of the point you wish to move. This routine
  183.  * will modify origin.
  184.  *
  185.  * limits specifies the bounding box that you wish origin to be contained
  186.  * within. It's format is limit[x=0, y=1, z=2][lo=0, hi=1]
  187.  * 
  188.  * See the comments in spaced.h for more implementation information.
  189.  */
  190. int spaced(Matrix M, Coord origin[3], Coord limit[3][2])
  191. {
  192.     /**************
  193.      * Declarations
  194.      **************/
  195.      
  196.      
  197.     /*
  198.      * Remember what mmode() the program is in; must save projection
  199.      * matrix if not MSINGLE
  200.      */
  201.     int old_mmode;
  202.  
  203.     /* Temporary matrix to squirrel away the projection matrix */
  204.     Matrix old_projection;
  205.     
  206.     /* endpoint of line in world space projected from mouse pos'n */
  207.     Coord p1[3],p2[3];
  208.  
  209.     /* dummy view object used to find that line using mapw */
  210.     static Object vobj;
  211.  
  212.     /* Dont want to waste time and memory recreating that object */
  213.     static Boolean object_created = FALSE;
  214.  
  215.     /* Mouse pos'n */
  216.     Scoord mouse[2];
  217.  
  218.     /* Screen coords of the point being moved */
  219.     Scoord screen_motion_point[2];
  220.     
  221.     /* Which axes mouse is between[axis 0,1][endpoint 0,1] */
  222.     static short between[2][2];
  223.  
  224.     /* Your basic first-year geometry stuff */
  225.     Coord dx,dy,dz,x_slope,y_slope,z_slope,
  226.             x_int,y_int,z_int,x_proj,x_proj2,y_proj,y_proj2,z_proj,z_proj2;
  227.  
  228.     /* Screen coords of the six axes endpoints
  229.        screen_axis[x,y,z][end 0,1][x,y] */
  230.     Scoord screen_axis[3][2][2];
  231.  
  232.     /* used in finding screen axes */
  233.     Coord temp[3];
  234.  
  235.     /* Is the point inside of the bounding volume ? */
  236.     Boolean within_bounds;
  237.  
  238.     
  239.     /* 
  240.      * which axes to ignore when moving:
  241.      * at corners, ignore 3 of them
  242.      * at edges, ignore 2 of them
  243.      * at wall, ignore 1 of them
  244.      * inside, ignore none
  245.      *
  246.      * ignore[][0] = axis, ignore[1] = endpt */
  247.     int ignore[3][2];
  248.     int ignore_counter = 0;
  249.  
  250.     /* loop variables */
  251.     int i,j;
  252.  
  253.     Scoord temp_axis[2][2];
  254.  
  255.     Boolean at_edge;
  256.  
  257.     /* constraint value to return */
  258.     int constraint_return = SP_NONE;
  259.  
  260.     /***********************
  261.      * Let the code begin...
  262.      ***********************/
  263.  
  264.     /* The mouse be here */
  265.     mouse[0] = getvaluator(MOUSEX);
  266.     mouse[1] = getvaluator(MOUSEY);
  267.  
  268.     /* what the window is like */
  269.     getorigin(&origin_x, &origin_y);
  270.     getsize(&size_x, &size_y);
  271.  
  272.     old_mmode = getmmode();
  273.     if (old_mmode != MSINGLE)
  274.     {
  275.         mmode(MPROJECTION);
  276.         getmatrix(old_projection);
  277.         loadmatrix(idmat);
  278.         mmode(MSINGLE);
  279.     }
  280.  
  281.     /* create the dummy view object, if necessary */
  282.     if (! object_created)
  283.     {
  284.         vobj = genobj();
  285.         makeobj(vobj); closeobj();
  286.         object_created = TRUE;
  287.     }
  288.  
  289.     /* use the current world->screen transformation */
  290.     pushmatrix();
  291.         delobj(vobj);
  292.         makeobj(vobj);
  293.             loadmatrix(M); 
  294.         closeobj();
  295.     popmatrix();
  296.  
  297.     /* find the line that the mouse position maps to in world space */
  298.     mapw(vobj, mouse[0]-origin_x, mouse[1]-origin_y,
  299.         &p1[0], &p1[1], &p1[2], &p2[0], &p2[1], &p2[2]);
  300.  
  301.     /* find screen coords of the axes */
  302.     for (i=0; i<3; i++)
  303.         for (j=0; j<2; j++)
  304.         {
  305.             temp[0] = origin[0];
  306.             temp[1] = origin[1];
  307.             temp[2] = origin[2];
  308.             temp[i] = limit[i][j];
  309.             transform_point(temp, M, screen_axis[i][j]);            
  310.         }
  311.  
  312.     /* and of the point in motion */
  313.     temp[0] = origin[0];
  314.     temp[1] = origin[1];
  315.     temp[2] = origin[2];
  316.     transform_point(temp, M, screen_motion_point);
  317.  
  318.     /* Check if constraining starts/stops */
  319.     plane_constrain = getbutton(plane_but1) || getbutton(plane_but2);
  320.     line_constrain = getbutton(line_but1) || getbutton(line_but2);
  321.  
  322.     /* Line constraining is more constraining then plane constraining (!) */
  323.     if (line_constrain)
  324.         plane_constrain = FALSE;
  325.     
  326.     /* Only pick a plane once if constraining, every time if not */
  327.     if ((! line_constrain) && (! plane_constrain))
  328.     {
  329.         plane = NONE;
  330.         constraint_ok = FALSE;
  331.         first_time = TRUE;
  332.     }
  333.     
  334.     /* Setup initial constraint conditions */
  335.     if ((line_constrain || plane_constrain) && first_time)
  336.     {
  337.         first_time = FALSE;
  338.         plane = NONE;
  339.         
  340.         initial_screen_origin[0] = screen_motion_point[0];
  341.         initial_screen_origin[1] = screen_motion_point[1];
  342.  
  343.         initial_origin[0] = origin[0];
  344.         initial_origin[1] = origin[1];
  345.         initial_origin[2] = origin[2];
  346.     }
  347.  
  348.  
  349.     /* Check boundary conditions
  350.      * Only do this once if constraining
  351.      */
  352.     if (plane == NONE)
  353.     {
  354.         within_bounds = TRUE;
  355.  
  356.         ignore_counter = 0;
  357.  
  358.         for(i=0; i<3; i++)
  359.             for(j=0; j<2; j++)
  360.                 if (origin[i] == limit[i][j])
  361.                 {
  362.                     within_bounds = FALSE;
  363.                     ignore[ignore_counter][0] = i;
  364.                     ignore[ignore_counter][1] = j;
  365.                     ignore_counter++;
  366.                 }
  367.     }
  368.     at_edge = (ignore_counter >= 2);
  369.  
  370.  
  371.     /* Check if mouse has moved far enough to do constrained motion */
  372.     if ((line_constrain || plane_constrain) &&
  373.         (plane == NONE) &&
  374.         (!constraint_ok))
  375.     {
  376.         temp_axis[0][0] = (Scoord)(mouse[0]);
  377.         temp_axis[0][1] = (Scoord)(mouse[1]);
  378.         
  379.         temp_axis[1][0] = initial_screen_origin[0];
  380.         temp_axis[1][1] = initial_screen_origin[1];
  381.  
  382.         constraint_ok = (length(temp_axis) > SP_CONSTRAINT_THRESHOLD);
  383.     }
  384.     
  385.  
  386.     /* Check for axis colinearity. Ignore shorter of two colinear axes */
  387.     if ((within_bounds) && (plane == NONE))
  388.     {
  389.         if (colinear(screen_axis[0],screen_axis[1]))
  390.             if (length(screen_axis[0]) < length(screen_axis[1]))
  391.             {
  392.                 ignore[ignore_counter][0] = 0;
  393.                 ignore[ignore_counter][1] = 0;
  394.                 ignore_counter++;
  395.                 ignore[ignore_counter][0] = 0;
  396.                 ignore[ignore_counter][1] = 1;
  397.                 ignore_counter++;
  398.             }
  399.             else
  400.             {
  401.                 ignore[ignore_counter][0] = 1;
  402.                 ignore[ignore_counter][1] = 0;
  403.                 ignore_counter++;
  404.                 ignore[ignore_counter][0] = 1;
  405.                 ignore[ignore_counter][1] = 1;
  406.                 ignore_counter++;
  407.             }
  408.         else if (colinear(screen_axis[0],screen_axis[2]))
  409.             if (length(screen_axis[0]) < length(screen_axis[2]))
  410.             {
  411.                 ignore[ignore_counter][0] = 0;
  412.                 ignore[ignore_counter][1] = 0;
  413.                 ignore_counter++;
  414.                 ignore[ignore_counter][0] = 0;
  415.                 ignore[ignore_counter][1] = 1;
  416.                 ignore_counter++;
  417.             }
  418.             else
  419.             {
  420.                 ignore[ignore_counter][0] = 2;
  421.                 ignore[ignore_counter][1] = 0;
  422.                 ignore_counter++;
  423.                 ignore[ignore_counter][0] = 2;
  424.                 ignore[ignore_counter][1] = 1;
  425.                 ignore_counter++;
  426.             }
  427.         else if (colinear(screen_axis[1],screen_axis[2]))
  428.             if (length(screen_axis[1]) < length(screen_axis[2]))
  429.             {
  430.                 ignore[ignore_counter][0] = 1;
  431.                 ignore[ignore_counter][1] = 0;
  432.                 ignore_counter++;
  433.                 ignore[ignore_counter][0] = 1;
  434.                 ignore[ignore_counter][1] = 1;
  435.                 ignore_counter++;
  436.             }
  437.             else
  438.             {
  439.                 ignore[ignore_counter][0] = 2;
  440.                 ignore[ignore_counter][1] = 0;
  441.                 ignore_counter++;
  442.                 ignore[ignore_counter][0] = 2;
  443.                 ignore[ignore_counter][1] = 1;
  444.                 ignore_counter++;
  445.             }
  446.     }
  447.  
  448.     
  449.  
  450.     if ((plane == NONE) && 
  451.         (((! line_constrain) && (! plane_constrain)) ||
  452.          ((line_constrain || plane_constrain) && (constraint_ok))))
  453.     {
  454.                 
  455.         find_close(
  456.         mouse,screen_motion_point,screen_axis,between,ignore,ignore_counter);
  457.  
  458.         if (! at_edge)
  459.         {
  460.             if ((between[0][0] != 0) && (between[1][0] != 0))
  461.                 plane = YZ;
  462.             else if ((between[0][0] != 1) && (between[1][0] != 1))
  463.                 plane = XZ;
  464.             else if ((between[0][0] != 2) && (between[1][0] != 2))
  465.                 plane = XY;
  466.         }
  467.         else
  468.         {
  469.             edge = between[0][0];
  470.             plane = EDGE_PICKED;
  471.         }
  472.     }
  473.  
  474.     /* Compute where the projected mouse position is */
  475.  
  476.     if ((! at_edge)&&(plane == YZ))
  477.     {
  478.         /* Motion in Y-Z plane, X constant
  479.             Find where line hits the x=0 plane
  480.             As always, y = mx + b */
  481.         dx = p2[0] - p1[0];
  482.         
  483.         if (dx != 0.0)
  484.         {
  485.             dy = p2[1] - p1[1];
  486.             dz = p2[2] - p1[2];
  487.  
  488.             y_slope = dy/dx;                
  489.             y_int = p2[1] - y_slope*p2[0]; /* at x = 0 */
  490.             y_proj = y_slope*origin[0] + y_int;
  491.  
  492.             z_slope = dz/dx;
  493.             z_int = p2[2] - z_slope*p2[0];
  494.             z_proj = z_slope*origin[0] + z_int;
  495.         }
  496.         else
  497.         {
  498.             y_proj = p2[1];
  499.             z_proj = p2[2];
  500.         }
  501.             
  502.         if ((! line_constrain) || (line_constrain && between[0][0] == 1) || 
  503.         plane_constrain)
  504.             if (y_proj <= limit[1][0])
  505.                 origin[1] = limit[1][0];
  506.             else if (y_proj >= limit[1][1])
  507.                 origin[1] = limit[1][1];
  508.             else
  509.                 origin[1] = y_proj;
  510.  
  511.         if ((! line_constrain) || (line_constrain && between[0][0] == 2) ||
  512.         plane_constrain)
  513.             if (z_proj <= limit[2][0])
  514.                 origin[2] = limit[2][0];
  515.             else if (z_proj >= limit[2][1])
  516.                 origin[2] = limit[2][1];
  517.             else
  518.                 origin[2] = z_proj;        
  519.     }
  520.     else if ((! at_edge)&&(plane == XZ))
  521.     {
  522.         /* Motion in X-Z plane, Y constant */
  523.             
  524.         dy = p2[1] - p1[1];
  525.  
  526.         if (dy != 0.0)
  527.         {
  528.             dx = p2[0] - p1[0];
  529.             dz = p2[2] - p1[2];
  530.  
  531.             x_slope = dx/dy;
  532.             x_int = p2[0] - x_slope*p2[1]; /* at y = 0 */
  533.             x_proj = x_slope*origin[1] + x_int;
  534.  
  535.             z_slope = dz/dy;
  536.             z_int = p2[2] - z_slope*p2[1];
  537.             z_proj = z_slope*origin[1] + z_int;
  538.         }
  539.         else
  540.         {
  541.             x_proj = p2[0];
  542.             z_proj = p2[2];
  543.         }
  544.  
  545.         if ((! line_constrain) || (line_constrain && between[0][0] == 0) ||
  546.         plane_constrain)
  547.             if (x_proj <= limit[0][0])
  548.                 origin[0] = limit[0][0];
  549.             else if (x_proj >= limit[0][1])
  550.                 origin[0] = limit[0][1];
  551.             else
  552.                 origin[0] = x_proj;
  553.  
  554.         if ((! line_constrain) || (line_constrain && between[0][0] == 2) ||
  555.         plane_constrain)
  556.             if (z_proj <= limit[2][0])
  557.                 origin[2] = limit[2][0];
  558.             else if (z_proj >= limit[2][1])
  559.                 origin[2] = limit[2][1];
  560.             else
  561.                 origin[2] = z_proj;
  562.                                             
  563.     }
  564.     else if ((! at_edge)&&(plane == XY))
  565.     {
  566.         /* Motion in X-Y plane, Z constant */
  567.         
  568.         dz = p2[2] - p1[2];
  569.  
  570.         if (dz != 0.0)
  571.         {
  572.             dx = p2[0] - p1[0];
  573.             dy = p2[1] - p1[1];
  574.  
  575.             x_slope = dx/dz;
  576.             x_int = p2[0] - x_slope*p2[2]; /* at z = 0 */
  577.             x_proj = x_slope*origin[2] + x_int;
  578.  
  579.             y_slope = dy/dz;
  580.             y_int = p2[1] - y_slope*p2[2];
  581.             y_proj = y_slope*origin[2] + y_int;
  582.         }
  583.         else
  584.         {
  585.             x_proj = p2[0];
  586.             y_proj = p2[1];
  587.         }
  588.             
  589.         if ((! line_constrain) || (line_constrain && between[0][0] == 0) ||
  590.         plane_constrain)
  591.             if (x_proj <= limit[0][0])
  592.                 origin[0] = limit[0][0];
  593.             else if (x_proj >= limit[0][1])
  594.                 origin[0] = limit[0][1];
  595.             else
  596.                 origin[0] = x_proj;
  597.     
  598.         if ((! line_constrain) || (line_constrain && between[0][0] == 1) ||
  599.         plane_constrain)
  600.             if (y_proj <= limit[1][0])
  601.                 origin[1] = limit[1][0];
  602.             else if (y_proj >= limit[1][1])
  603.                 origin[1] = limit[1][1];
  604.             else
  605.                 origin[1] = y_proj;
  606.     }
  607.     else if (edge == X)
  608.     {
  609.         float cos_angle,base,hyp,slength,q1[3],q2[3];
  610.         Scoord sdx,sdy,newx,newy;
  611.     
  612.         cos_angle=cos_angle_between(screen_axis[0][0],screen_axis[0][1],mouse);
  613.  
  614.         hyp = dist(screen_axis[0][0],mouse);
  615.         base = hyp * cos_angle;
  616.  
  617.         sdx = screen_axis[0][1][0] - screen_axis[0][0][0];
  618.         sdy = screen_axis[0][1][1] - screen_axis[0][0][1];
  619.         slength = fsqrt((float)(sdx*sdx + sdy*sdy));
  620.         
  621.         newx = (Scoord) ( (float)screen_axis[0][0][0] + 
  622.         ((float)(screen_axis[0][1][0] - screen_axis[0][0][0]))*(base/slength));
  623.  
  624.         newy = (Scoord) ( (float)screen_axis[0][0][1] + 
  625.         ((float)(screen_axis[0][1][1] - screen_axis[0][0][1]))*(base/slength));
  626.  
  627.         mapw(vobj, newx-origin_x, newy-origin_y,
  628.             &q1[0], &q1[1], &q1[2], &q2[0], &q2[1], &q2[2]);
  629.             
  630.         /* in XY plane... */
  631.         
  632.         dz = q2[2] - q1[2];
  633.  
  634.         if (dz != 0.0)
  635.         {
  636.             dx = q2[0] - q1[0];
  637.             dy = q2[1] - q1[1];
  638.  
  639.             x_slope = dx/dz;
  640.             x_int = q2[0] - x_slope*q2[2]; /* at z = 0 */
  641.             x_proj = x_slope*origin[2] + x_int;
  642.  
  643.             y_slope = dy/dz;
  644.             y_int = q2[1] - y_slope*q2[2];
  645.             y_proj = y_slope*origin[2] + y_int;
  646.         }
  647.         else
  648.         {
  649.             x_proj = q2[0];
  650.             y_proj = q2[1];
  651.         }
  652.         
  653.         /* in XZ plane... */
  654.  
  655.         dy = q2[1] - q1[1];
  656.  
  657.         if (dy != 0.0)
  658.         {
  659.             dx = q2[0] - q1[0];
  660.             dz = q2[2] - q1[2];
  661.  
  662.             x_slope = dx/dy;
  663.             x_int = q2[0] - x_slope*q2[1]; /* at y = 0 */
  664.             x_proj2 = x_slope*origin[1] + x_int;
  665.  
  666.             z_slope = dz/dy;
  667.             z_int = q2[2] - z_slope*q2[1];
  668.             z_proj = z_slope*origin[1] + z_int;
  669.         }
  670.         else
  671.         {
  672.             x_proj2 = q2[0];
  673.             z_proj = q2[2];
  674.         }
  675.  
  676.  
  677.         origin[0] = x_proj - ((y_proj - origin[1])*(x_proj -
  678.                     x_proj2)/(y_proj-z_proj));
  679.  
  680.         
  681.         if (origin[0] < limit[0][0])
  682.             origin[0] = limit[0][0];
  683.         else if (origin[0] > limit[0][1])
  684.             origin[0] = limit[0][1];
  685.  
  686.  
  687.             
  688.     }    
  689.     else if (edge == Y)
  690.     {
  691.         float cos_angle,base,hyp,slength,q1[3],q2[3];
  692.         Scoord sdx,sdy,newx,newy;
  693.     
  694.         cos_angle=cos_angle_between(screen_axis[1][0],screen_axis[1][1],mouse);
  695.  
  696.         hyp = dist(screen_axis[1][0],mouse);
  697.         base = hyp * cos_angle;
  698.  
  699.         sdx = screen_axis[1][1][0] - screen_axis[1][0][0];
  700.         sdy = screen_axis[1][1][1] - screen_axis[1][0][1];
  701.         slength = fsqrt((float)(sdx*sdx + sdy*sdy));
  702.         
  703.         newx = (Scoord) ( (float)screen_axis[1][0][0] + 
  704.         ((float)(screen_axis[1][1][0] - screen_axis[1][0][0]))*(base/slength));
  705.  
  706.         newy = (Scoord) ( (float)screen_axis[1][0][1] + 
  707.         ((float)(screen_axis[1][1][1] - screen_axis[1][0][1]))*(base/slength));
  708.  
  709.         mapw(vobj, newx-origin_x, newy-origin_y,
  710.             &q1[0], &q1[1], &q1[2], &q2[0], &q2[1], &q2[2]);
  711.         
  712.         /* in XY plane... */
  713.         
  714.         dz = q2[2] - q1[2];
  715.  
  716.         if (dz != 0.0)
  717.         {
  718.             dx = q2[0] - q1[0];
  719.             dy = q2[1] - q1[1];
  720.  
  721.             x_slope = dx/dz;
  722.             x_int = q2[0] - x_slope*q2[2]; /* at z = 0 */
  723.             x_proj = x_slope*origin[2] + x_int;
  724.  
  725.             y_slope = dy/dz;
  726.             y_int = q2[1] - y_slope*q2[2];
  727.             y_proj = y_slope*origin[2] + y_int;
  728.         }
  729.         else
  730.         {
  731.             x_proj = q2[0];
  732.             y_proj = q2[1];
  733.         }
  734.         
  735.         /* in YZ plane... */
  736.         dx = q2[0] - q1[0];
  737.         
  738.         if (dx != 0.0)
  739.         {
  740.             dy = q2[1] - q1[1];
  741.             dz = q2[2] - q1[2];
  742.  
  743.             y_slope = dy/dx;                
  744.             y_int = q2[1] - y_slope*q2[0]; /* at x = 0 */
  745.             y_proj2 = y_slope*origin[0] + y_int;
  746.  
  747.             z_slope = dz/dx;
  748.             z_int = q2[2] - z_slope*q2[0];
  749.             z_proj = z_slope*origin[0] + z_int;
  750.         }
  751.         else
  752.         {
  753.             y_proj2 = q2[1];
  754.             z_proj = q2[2];
  755.         }
  756.  
  757.         
  758.         origin[1] = y_proj2 - ((z_proj - origin[0])*(y_proj2 -
  759.         y_proj)/(z_proj-x_proj));
  760.         
  761.         if (origin[1] < limit[1][0])
  762.             origin[1] = limit[1][0];
  763.         else if (origin[1] > limit[1][1])
  764.             origin[1] = limit[1][1];
  765.     }
  766.     else if (edge == Z)
  767.     {
  768.         float cos_angle,base,hyp,slength,q1[3],q2[3];
  769.         Scoord sdx,sdy,newx,newy;
  770.     
  771.         cos_angle=cos_angle_between(screen_axis[2][0],screen_axis[2][1],mouse);
  772.  
  773.         hyp = dist(screen_axis[2][0],mouse);
  774.         base = hyp * cos_angle;
  775.  
  776.         sdx = screen_axis[2][1][0] - screen_axis[2][0][0];
  777.         sdy = screen_axis[2][1][1] - screen_axis[2][0][1];
  778.         slength = fsqrt((float)(sdx*sdx + sdy*sdy));
  779.         
  780.         newx = (Scoord) ( (float)screen_axis[2][0][0] + 
  781.         ((float)(screen_axis[2][1][0] - screen_axis[2][0][0]))*(base/slength));
  782.  
  783.         newy = (Scoord) ( (float)screen_axis[2][0][1] + 
  784.         ((float)(screen_axis[2][1][1] - screen_axis[2][0][1]))*(base/slength));
  785.  
  786.         mapw(vobj, newx-origin_x, newy-origin_y,
  787.             &q1[0], &q1[1], &q1[2], &q2[0], &q2[1], &q2[2]);
  788.  
  789.         /* in XZ plane... */
  790.  
  791.         dy = q2[1] - q1[1];
  792.  
  793.         if (dy != 0.0)
  794.         {
  795.             dx = q2[0] - q1[0];
  796.             dz = q2[2] - q1[2];
  797.  
  798.             x_slope = dx/dy;
  799.             x_int = q2[0] - x_slope*q2[1]; /* at y = 0 */
  800.             x_proj = x_slope*origin[1] + x_int;
  801.  
  802.             z_slope = dz/dy;
  803.             z_int = q2[2] - z_slope*q2[1];
  804.             z_proj = z_slope*origin[1] + z_int;
  805.         }
  806.         else
  807.         {
  808.             x_proj = q2[0];
  809.             z_proj = q2[2];
  810.         }
  811.         
  812.         /* in YZ plane... */
  813.         dx = q2[0] - q1[0];
  814.         
  815.         if (dx != 0.0)
  816.         {
  817.             dy = q2[1] - q1[1];
  818.             dz = q2[2] - q1[2];
  819.  
  820.             y_slope = dy/dx;                
  821.             y_int = q2[1] - y_slope*q2[0]; /* at x = 0 */
  822.             y_proj = y_slope*origin[0] + y_int;
  823.  
  824.             z_slope = dz/dx;
  825.             z_int = q2[2] - z_slope*q2[0];
  826.             z_proj2 = z_slope*origin[0] + z_int;
  827.         }
  828.         else
  829.         {
  830.             y_proj = q2[1];
  831.             z_proj2 = q2[2];
  832.         }
  833.  
  834.  
  835.         origin[2] = z_proj2 - ((x_proj - origin[1])*(z_proj2 -
  836.         z_proj)/(x_proj-y_proj));
  837.         
  838.         if (origin[2] < limit[2][0])
  839.             origin[2] = limit[2][0];
  840.         else if (origin[2] > limit[2][1])
  841.             origin[2] = limit[2][1];
  842.             
  843.  
  844.     }
  845.  
  846.     if (old_mmode != MSINGLE);
  847.     {
  848.         mmode(MPROJECTION);
  849.         loadmatrix(old_projection);
  850.         mmode(old_mmode);
  851.     }
  852.  
  853.     if (plane_constrain)
  854.         switch (plane)
  855.         {
  856.             case YZ: constraint_return = SP_YZ_PLANE; break;
  857.             case XZ: constraint_return = SP_XZ_PLANE; break;
  858.             case XY: constraint_return = SP_XY_PLANE; break;
  859.         }
  860.     else if (line_constrain)
  861.         switch (plane)
  862.         {
  863.             case YZ:
  864.                 if (between[0][0] == 2)
  865.                     constraint_return = SP_Z_AXIS;
  866.                 else
  867.                     constraint_return = SP_Y_AXIS;
  868.                 break;
  869.             case XZ:
  870.                 if (between[0][0] == 2)
  871.                     constraint_return = SP_Z_AXIS;
  872.                 else
  873.                     constraint_return = SP_X_AXIS;
  874.                 break;
  875.             case XY:
  876.                 if (between[0][0] == 1)
  877.                     constraint_return = SP_Y_AXIS;
  878.                 else
  879.                     constraint_return = SP_X_AXIS;
  880.                 break;
  881.         }
  882.     return constraint_return;
  883. }
  884.  
  885.  
  886. /* In variable between, returns which two axis the mouse position is
  887.  * between. There are six possible axes, pos and neg for each of x,y,z.
  888.  * The closest axis to the mouse position will be in between[0], and
  889.  * the next closest will be in between[1].
  890.  * 
  891.  * if ignore is set to 0,1 or 2, that axis will be ignore.
  892.  * 
  893.  * Example: if
  894.  *  between[0][0] = 1, between[0][1] = 0
  895.  *  between[1][0] = 2, between[1][1] = 1
  896.  *
  897.  * means that the mouse is between axis 1, endpoint 0 and axis 2, endpoint 1.
  898.  * Translated, the mouse is between the negative Y and positive Z axes,
  899.  * closer to Y.
  900.  */
  901. static void find_close(
  902.     Scoord mouse[2],
  903.     Scoord center[2], 
  904.     Scoord screen_axis[3][2][2], 
  905.     short between[2][2],
  906.     int ignore[3][2],
  907.     int ignore_counter)
  908. {
  909.     short i, j, k;
  910.     float distance,max1,max2;
  911.  
  912.     max1 = max2 = -2.0; /* nothing will ever be less than -1.0 */
  913.  
  914.     /* find distance from mouse vector to the six axes */
  915.     for(i=0;i<3;i++)
  916.         for(j=0;j<2;j++)
  917.         {
  918.             distance = 0.0;
  919.             
  920.             for (k=0; k<ignore_counter; k++)
  921.                 if ((i == ignore[k][0]) && (j == ignore[k][1]))
  922.                     distance = -2.0;
  923.  
  924.             if (distance == 0.0)
  925.                 distance = find_distance(center, mouse, screen_axis[i][j] );
  926.  
  927.             if (distance > max1)
  928.             {
  929.                 between[1][0] = between[0][0];
  930.                 between[1][1] = between[0][1];
  931.  
  932.                 between[0][0] = i;
  933.                 between[0][1] = j;
  934.                 
  935.                 max2 = max1;
  936.                 max1 = distance;
  937.             }
  938.             else if (distance > max2)
  939.             {
  940.                 between[1][0] = i;
  941.                 between[1][1] = j;
  942.                 
  943.                 max2 = distance;
  944.             }
  945.  
  946.         }
  947. }
  948.  
  949.  
  950. /* Returns the length of the axis. */
  951. static int length(Scoord axis[2][2])
  952. {
  953.     int dx,dy;
  954.  
  955.     dx = axis[1][0] - axis[0][0];
  956.     dy = axis[1][1] - axis[0][1];
  957.  
  958.     return ((int)fsqrt((float)(dx*dx + dy*dy)));
  959. }
  960.  
  961.     
  962.  
  963.  
  964. /* Finds the "distance" between the two vectors from center to p1, and
  965.  * center to p2. Actually returns the dot product, normalized 0.0 to 1.0.
  966.  */
  967. static float find_distance(Scoord center[2], Scoord p1[2], Scoord p2[2])
  968. {
  969.     float result,v1[2],v2[2],n1,n2;
  970.  
  971.     v1[0] = (float)p1[0] - (float)center[0];
  972.     v1[1] = (float)p1[1] - (float)center[1];
  973.  
  974.     v2[0] = (float)p2[0] - (float)center[0];
  975.     v2[1] = (float)p2[1] - (float)center[1];
  976.  
  977.     n1 = fsqrt(v1[0]*v1[0] + v1[1]*v1[1]);
  978.     n2 = fsqrt(v2[0]*v2[0] + v2[1]*v2[1]);
  979.  
  980.     result = (v1[0]/n1)*(v2[0]/n2) + (v1[1]/n1)*(v2[1]/n2);
  981.  
  982.     return(result);
  983. }
  984.  
  985. /*
  986. Returns the cosine of angle between the vectors P1 and P2 with common start
  987. point center
  988. */
  989. static float cos_angle_between(Scoord center[2], Scoord p1[2], Scoord p2[2])
  990. {
  991.     float v1[2],v2[2],n1,n2;
  992.  
  993.     v1[0] = (float)p1[0] - (float)center[0];
  994.     v1[1] = (float)p1[1] - (float)center[1];
  995.  
  996.     v2[0] = (float)p2[0] - (float)center[0];
  997.     v2[1] = (float)p2[1] - (float)center[1];
  998.  
  999.     n1 = fsqrt(v1[0]*v1[0] + v1[1]*v1[1]);
  1000.     n2 = fsqrt(v2[0]*v2[0] + v2[1]*v2[1]);
  1001.  
  1002.     return (v1[0]*v2[0] + v1[1]*v2[1])/(n1*n2);
  1003. }
  1004.  
  1005.  
  1006. static float dist(Scoord p1[2], Scoord p2[2])
  1007. {
  1008.     float result,v1[2];
  1009.  
  1010.     v1[0] = (float)p2[0] - (float)p1[0];
  1011.     v1[1] = (float)p2[1] - (float)p1[1];
  1012.  
  1013.     return fsqrt(v1[0]*v1[0] + v1[1]*v1[1]);
  1014. }
  1015.     
  1016.     
  1017.  
  1018. /*
  1019.  * Takes a world coordinate (x,y,z) and pumps it through tranformation
  1020.  * matrix M, returning the screen coordinate in result.
  1021.  *
  1022.  * Note: One could use feedback to do this, but it turns out to be
  1023.  * faster to do it manually.
  1024.  */
  1025. static void transform_point(Coord *p, Matrix M, Scoord *result)
  1026. {
  1027.     Coord x,y,z,w,hx,hy;
  1028.  
  1029.     x = p[0]*M[0][0] + p[1]*M[1][0] + p[2]*M[2][0] + M[3][0];
  1030.     y = p[0]*M[0][1] + p[1]*M[1][1] + p[2]*M[2][1] + M[3][1];
  1031.     z = p[0]*M[0][2] + p[1]*M[1][2] + p[2]*M[2][2] + M[3][2]; 
  1032.     w = p[0]*M[0][3] + p[1]*M[1][3] + p[2]*M[2][3] + M[3][3];
  1033.  
  1034.     /* Homogeneous coords b/w -1 and 1 */
  1035.     hx = x/w;
  1036.     hy = y/w;
  1037.  
  1038.     result[0] = (Scoord)((1.0 + hx)*(Coord)size_x/2.0) + origin_x;
  1039.     result[1] = (Scoord)((1.0 + hy)*(Coord)size_y/2.0) + origin_y;
  1040. }
  1041.  
  1042.  
  1043. /*
  1044.  * Returns TRUE if the two axes are colinear within COLINEAR_THRESHOLD
  1045.  * pixels.
  1046.  *
  1047.  * Finds the distance from endpoint of one two line of other.
  1048.  * Taken from handbook of mathematical tables... p. 159
  1049.  */
  1050. static Boolean colinear(Scoord a1[2][2], Scoord a2[2][2])
  1051. {
  1052.     float dx,dy,m,b,A,B,C,dist1,dist2;
  1053.     
  1054.     dx = (float)(a1[0][0] - a1[1][0]);
  1055.  
  1056.     if (dx == 0.0)
  1057.         dx = 0.0001;
  1058.  
  1059.     dy = (float)(a1[0][1] - a1[1][1]);
  1060.  
  1061.     m = dy/dx; /* slope */
  1062.     b = (float)a1[0][1] - m*(float)a1[0][0]; /* y intercept */
  1063.  
  1064.     A = -m;
  1065.     B = 1.0;
  1066.     C = -b;
  1067.  
  1068.     dist1 = (A*(float)a2[0][0] + B*(float)a2[0][1] + C)/
  1069.             fsqrt(A*A + B*B);
  1070.  
  1071.     dist2 = (A*(float)a2[1][0] + B*(float)a2[1][1] + C)/
  1072.             fsqrt(A*A + B*B);
  1073.  
  1074.     if ((fabs(dist1) < (float)SP_COLINEAR_THRESHOLD) && (fabs(dist2) < (float)SP_COLINEAR_THRESHOLD))
  1075.         return TRUE;
  1076.     else
  1077.         return FALSE;
  1078. }
  1079.  
  1080.  
  1081.  
  1082.